package com.tianji.promotion.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CategoryClient;
import com.tianji.api.dto.course.CategoryBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.po.UserCoupon;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponDetailVO;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponScopeVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.enums.UserCouponStatus;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.service.IUserCouponService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author ffk
 * @since 2024-07-02
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {


    private  final ICouponScopeService couponScopeService;
    private final IExchangeCodeService exchangeCodeService;
    private  final CategoryClient categoryClient;
    private final IUserCouponService userCouponService;

    /**
     * 新增优惠券
     * @param couponFormDTO 前端传入的优惠券信息
     */
    @Override
    public void addCoupon(CouponFormDTO couponFormDTO) {

        Coupon coupon = BeanUtils.toBean(couponFormDTO, Coupon.class);
        boolean result = save(coupon);
        if(!result){
            throw new BizIllegalException("新增优惠券失败");
        }

        if(ObjectUtils.isEmpty(couponFormDTO.getScopes()) || coupon.getSpecific()==null){
            // 没有限定使用范围,不用写入优惠券作用范围信息表
            return;
        }

        Long couponId = coupon.getId();

        //限定的分类id
        List<Long> scopesIds = couponFormDTO.getScopes();
        if(ObjectUtils.isEmpty(scopesIds)){
            throw new BizIllegalException("限定的分类id不能为空");
        }

        List<CouponScope> couponList = new ArrayList<>();

        for (Long scopesId : scopesIds) {
            CouponScope couponScope = new CouponScope();
            couponScope.setBizId(scopesId);
            couponScope.setCouponId(couponId);
            couponList.add(couponScope);
        }

        boolean resultCouponResult = couponScopeService.saveBatch(couponList);

        if(!resultCouponResult){
            throw new BizIllegalException("新增到优惠券作用范围信息表失败");
        }

    }

    /**
     * 分页查询优惠券
     * @param couponQuery 折扣类型，优惠券状态，优惠券关键字，分页参数
     * @return
     */
    @Override
    public PageDTO<CouponPageVO> pageQueryCoupon(CouponQuery couponQuery) {
        Page<Coupon> pageInfo = lambdaQuery().eq(ObjectUtils.isNotEmpty(couponQuery.getType()), Coupon::getType, couponQuery.getType())
                .eq(ObjectUtils.isNotEmpty(couponQuery.getStatus()), Coupon::getStatus, couponQuery.getStatus())
                .like(ObjectUtils.isNotEmpty(couponQuery.getName()), Coupon::getName, couponQuery.getName())
                .page(couponQuery.toMpPageDefaultSortByCreateTimeDesc());

        if(ObjectUtils.isEmpty(pageInfo)){
            return PageDTO.empty(0L,0L);
        }

        List<Coupon> records = pageInfo.getRecords();
        if(ObjectUtils.isEmpty(records)){
            return PageDTO.empty(pageInfo);
        }

        List<CouponPageVO> couponPageVOS = BeanUtils.copyList(records, CouponPageVO.class);

        return PageDTO.of(pageInfo,couponPageVOS);
    }

    /**
     * 发放优惠券,实际上就是修改优惠券的状态
     * @param id 优惠券id
     * @param couponIssueFormDTO 发放起止时间，使用有效期起止时间
     */
    @Override
    public void giveSomeCoupon(Long id, CouponIssueFormDTO couponIssueFormDTO) {
        log.info("看一下id接收到没有：{}",id);
        Coupon coupon = this.getById(id);
        if(ObjectUtils.isEmpty(coupon)){
            throw new BizIllegalException("优惠券不存在,不用发了");
        }

        //只有暂停和待发放是 可能需要发放优惠券的

        if(coupon.getStatus()!=CouponStatus.DRAFT && coupon.getStatus()!= CouponStatus.PAUSE){
            throw new BizIllegalException("优惠券状态不是待发放或暂停，不能发放优惠券");
        }


        LocalDateTime now = LocalDateTime.now();
        //是立即发送还是定时发送
        // 开始时间为null,立即发送，过了定时设置的开始时间，立即发送
        boolean flag=couponIssueFormDTO.getIssueBeginTime()==null || !now.isBefore(couponIssueFormDTO.getIssueBeginTime());

        Coupon couponSave = BeanUtils.copyBean(couponIssueFormDTO, Coupon.class);

        if(flag){//立即
            couponSave.setIssueBeginTime(now);
            couponSave.setStatus(CouponStatus.ISSUING);
        }

        if(!flag){//定时
            couponSave.setStatus(CouponStatus.UN_ISSUE);
        }

        //存db
        updateById(couponSave);

        //是兑换码而且必须是待发放的才需要生成兑换码，暂停不重新生成，不然重复生成
        if(coupon.getObtainWay()== ObtainType.ISSUE && coupon.getStatus()== CouponStatus.DRAFT){
            coupon.setIssueEndTime(couponSave.getIssueEndTime());
            exchangeCodeService.generateCodeAsync(coupon);
        }

    }

    /**
     * 修改优惠券
     * @param couponFormDTO 修改了的参数
     */
    @Transactional
    @Override
    public void updateCoupon(CouponFormDTO couponFormDTO) {
        Coupon coupon = getById(couponFormDTO.getId());

        if(ObjectUtils.isEmpty(coupon)){
            throw new BizIllegalException("优惠券不存在,怎么更新？");
        }
        if(coupon.getStatus()!=CouponStatus.DRAFT){
            throw new BizIllegalException("优惠券状态不是待发放，不可以修改噢");
        }

        Coupon coupon1 = BeanUtils.copyBean(couponFormDTO, Coupon.class);
        //保存
        boolean result = updateById(coupon1);

        if(!result){
            throw new BizIllegalException("修改优惠券失败寄");
        }

        if(ObjectUtils.isEmpty(couponFormDTO.getScopes()) || coupon.getSpecific()==null){
            // 没有限定使用范围,不用更新优惠券作用范围信息表
            return;
        }

        //限定范围
        Long id = couponFormDTO.getId();
        List<Long> scopes = couponFormDTO.getScopes();

        //先删后增
        QueryWrapper<CouponScope> del = new QueryWrapper<CouponScope>()
                .eq("coupon_id", id);
        couponScopeService.remove(del);

        //增加
        List<CouponScope> addList=new ArrayList<>(scopes.size()+1);
        for (Long scope : scopes) {
         addList.add(new CouponScope().setCouponId(id)
                 .setBizId(scope));
        }

        couponScopeService.saveBatch(addList);
    }

    /**
     * 根据id查询优惠券
     * @param id 优惠券id
     * @return 信息
     */
    @Override
    public CouponDetailVO getCouponById(Long id) {
        Coupon coupon = getById(id);
        if(ObjectUtils.isEmpty(coupon)){
            throw new BizIllegalException("优惠券不存在");
        }
        CouponDetailVO couponDetailVO = BeanUtils.copyBean(coupon, CouponDetailVO.class);

        if(!coupon.getSpecific()){
            log.info("优惠券没有限定使用范围,直接返回");
            couponDetailVO.setScopes(null);
            return couponDetailVO;
        }

        //限定，查作用范围
        List<CouponScope> scopeMsg = couponScopeService.lambdaQuery()
                .eq(CouponScope::getCouponId, id)
                .list();
        if(ObjectUtils.isEmpty(scopeMsg)){
            throw new BizIllegalException("优惠券作用范围信息为空，但我限定了范围的，有问题");
        }
        //分类id
        Set<Long> bizIds = scopeMsg.stream().map(CouponScope::getBizId).collect(Collectors.toSet());

        //所有分类信息
        List<CategoryBasicDTO> allCategory = categoryClient.getAllOfOneLevel();
        if(ObjectUtils.isEmpty(allCategory)){
            throw new BizIllegalException("优惠券远程调用课程微服务，课程信息查不到呢宝");
        }

        //需要查询的分类id的信息
        Map<Long, String> msgMap = allCategory.stream()
                .filter(categoryBasicDTO -> bizIds.contains(categoryBasicDTO.getId()))
                .collect(Collectors.toMap(CategoryBasicDTO::getId,
                        categoryBasicDTO -> findTopCategoryName(allCategory,categoryBasicDTO)
                ));

        List<CouponScopeVO> scopeList=new ArrayList<>(coupon.getTotalNum());

        for (Long bizId : bizIds) {
            CouponScopeVO couponScopeVO = new CouponScopeVO();
            couponScopeVO.setId(bizId);
            couponScopeVO.setName(msgMap.get(bizId));
            scopeList.add(couponScopeVO);
        }

        couponDetailVO.setScopes(scopeList);
        return couponDetailVO;
    }

    /**
     * 删除优惠券
     * @param id 优惠券id
     */
    @Override
    public void deleteById(Long id) {
        Coupon coupon = getById(id);
        if(ObjectUtils.isEmpty(coupon)){
            throw new BizIllegalException("优惠券不存在,怎么删?");
        }

        CouponStatus status = coupon.getStatus();

        if(status==CouponStatus.DRAFT){
            log.info("优惠券状态是待发放，可以删除");
            removeById(id);
        }
    }

    /**
     * 暂停发放优惠券
     * @param id 优惠券id
     */
    @Override
    public void pauseCoupon(Long id) {
        // TODO: 2024/7/4
    }

    /**
     * 查询发放中的优惠券列表
     * @return 优惠券信息列表,包含优惠券信息，是否可以领取，是否可使用
     */
    @Override
    public List<CouponVO> queryIssuingCoupons() {

        //查出发放中，且为手动领取的优惠券
        List<Coupon> msgList = this.lambdaQuery()
                .eq(Coupon::getStatus, CouponStatus.ISSUING)
                .eq(Coupon::getObtainWay, ObtainType.PUBLIC)
                .list();
        if(ObjectUtils.isEmpty(msgList)){
            log.warn("没有发放中且可领取的优惠券");
            return Collections.emptyList();
        }

        //要查用户优惠券中间表，因为需要知道该用户对某个优惠券的领取状态，先收集发放中的优惠券id
        List<Long> couponIds = msgList.stream().map(Coupon::getId).collect(Collectors.toList());

        //用户优惠券中间表具体信息
        List<UserCoupon> userCouponMsg = userCouponService.lambdaQuery()
                .eq(UserCoupon::getUserId, UserContext.getUser())
                .in(ObjectUtils.isNotEmpty(couponIds), UserCoupon::getCouponId, couponIds)
                .list();

        //
        Map<Long, Long> countMap = userCouponMsg.stream()
                .collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));


        //状态是未使用的

        Map<Long, Long> statusMap = userCouponMsg.stream()
                .filter(userCoupon -> UserCouponStatus.UNUSED == userCoupon.getStatus())
                .collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));


        List<CouponVO> voList=new ArrayList<>(msgList.size());
        for (Coupon coupon : msgList) {
            CouponVO couponVO = BeanUtils.copyBean(coupon, CouponVO.class);

            //是否可领取，领取数<用户限制数 && 发放数<发放总数
            couponVO.setAvailable(countMap.getOrDefault(coupon.getId(), 0L)< coupon.getUserLimit()
                    && coupon.getIssueNum()<coupon.getTotalNum());

            //是否可使用,领取但没用
            couponVO.setReceived(statusMap.getOrDefault(coupon.getId(), 0L)>0);

            voList.add(couponVO);
        }

        return voList;
    }

    private String findTopCategoryName(List<CategoryBasicDTO> allCategory, CategoryBasicDTO categoryBasicDTO) {
        Long parentId = categoryBasicDTO.getParentId();
        if(parentId==0){
            return categoryBasicDTO.getName();
        }

        StringBuilder sb = new StringBuilder();
        sb.append(categoryBasicDTO.getName());
        //String cateName[]=new String[3];
       // int flag=1;
        while(true){
            //找父类
            Optional<CategoryBasicDTO> first = getParent(allCategory, parentId);
            if (first.isPresent()) {
                //存在,赋值
                String name = first.get().getName();
                parentId = first.get().getParentId();

                if(sb.length()>0){
                    sb.insert(0,"/");
                }

                sb.insert(0,name);

//                StringBuilder temp = new StringBuilder();
//                if(flag==1){
//                    sb.append(temp.append(name).reverse());
//                    flag=-1;
//                }else {
//                    sb.append("/").append(temp.append(name).reverse());
//                }

            }else{
                throw  new BizIllegalException("找顶级课程分类名称出错");
            }

            if(parentId==0){
                break;
            }
        }

        return sb.toString();
    }
    private Optional<CategoryBasicDTO> getParent(List<CategoryBasicDTO> allCategory, Long parentId) {
        return allCategory.stream()
                .filter(c -> c.getId().equals(parentId))
                .findFirst();
    }

}
